package cn.laoma.thread2.t2_002;

import lombok.SneakyThrows;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * @program: ThreadDemos
 * @description: 比较常用计算++的三种方式。
 * 说明：longAdder采用类似分段锁。线程数越多优势越明显
 * （1）LongAdder通过base和cells数组来存储值；
 * （2）不同的线程会hash到不同的cell上去更新，减少了竞争；
 * （3）LongAdder的性能非常高，最终会达到一种无竞争的状态；
 * 这里看下LongAdder原理图.jpg
 * @author: 老马
 * @create: 2021-10-24 09:58
 **/
public class Cas_02SyncAtomicLongAdder {
    static long count1 = 0;
    static AtomicLong count2 = new AtomicLong(0);
    static LongAdder count3 = new LongAdder();

    public static void main(String[] args) {
        Thread[] threads = new Thread[1000];

        //count1 : 采用synchronized方式
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 100000; j++) {
                    synchronized (Cas_02SyncAtomicLongAdder.class) {
                        count1 ++;
                    }
                }
            });
        }
        showTime(threads, "采用synchronized方式用时：");


        //count2 : 采用AtomicLong方式
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 100000; j++) {
                    count2.incrementAndGet();
                }
            });
        }
        showTime(threads, "采用AtomicLong方式用时：");


        //count3 : 采用LongAdder方式
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 100000; j++) {
                    count3.increment();
//                    count3.add(1);
                }
            });
        }
        showTime(threads, "采用LongAdder方式用时：");

    }

    @SneakyThrows
    static void showTime(Thread[] threads, String method) {
        long startTime = System.currentTimeMillis();
        for (Thread thread : threads) thread.start();
        for (Thread thread : threads) thread.join();
        long endTime = System.currentTimeMillis();
        if(method.indexOf("synchronized")!=-1) {
            System.out.println("count1=" + count1 + "," + method + (endTime - startTime));
        }else if(method.indexOf("AtomicLong")!=-1) {
            System.out.println("count2=" + count2 + "," + method + (endTime - startTime));
        }else if(method.indexOf("LongAdder")!=-1) {
            System.out.println("count3=" + count3 + "," + method + (endTime - startTime));
        }
    }

}
